#include "long_cmd.h"
// typedef struct train_s{
//     int length; //  火车头 固定4Bytes
//     int _cmdType;   //  命令类型
//     char data[1024];    //  火车车厢 上限为1024byte
// }train_t;
//
// train_t entrain(char* str,int len){    //  根据字符串创建小火车
//     train_t train;
//     train.length = len;
//     memcpy(train.data,str,len);
//     return train;
// }
void splitString(const char *pstrs, const char *delimiter, char *tokens[],
                 int max_tokens, int *pcount)
{ //  pstrs:待处理字符串  delimiter:分段标识符
  //  token[]:存放拆分的词组  pcount:拆分后词组的个数
    int token_count = 0;
    char *token = strtok((char *)pstrs, delimiter); // 使用delimiter作为分隔符

    while (token != NULL && token_count < max_tokens - 1)
    { // 保留一个位置给NULL终止符
        char *pstr = (char *)calloc(1, strlen(token) + 1);
        strcpy(pstr, token);
        tokens[token_count] = pstr; // 保存申请的堆空间首地址
        token_count++;
        token = strtok(NULL, delimiter); // 继续获取下一个token
    }
    // 添加NULL终止符
    tokens[token_count] = NULL;
    *pcount = token_count;
}

int getCommandType(const char *str)
{
    if (!strcmp(str, "pwd"))
    {
        return CMD_TYPE_PWD;
    }
    else if (!strcmp(str, "ls"))
    {
        return CMD_TYPE_LS;
    }
    else if (!strcmp(str, "cd"))
    {
        return CMD_TYPE_CD;
    }
    else if (!strcmp(str, "mkdir"))
    {
        return CMD_TYPE_MKDIR;
    }
    else if (!strcmp(str, "rmdir"))
    {
        return CMD_TYPE_RMDIR;
    }
    else if (!strcmp(str, "puts"))
    {
        return CMD_TYPE_PUTS;
    }
    else if (!strcmp(str, "gets"))
    {
        return CMD_TYPE_GETS;
    }
    else
    {
        return CMD_TYPE_NOTCMD;
    }
}
// 解析命令
int parseCommand(const char *pinput, train_t *pt)
{
    char *pstrs[10] = {0};
    int cnt = 0;
    splitString(pinput, " ", pstrs, 10, &cnt);
    pt->_cmdType = getCommandType(pstrs[0]);
    // 暂时限定命令行格式为：
    // 1. cmd
    // 2. cmd content
    if (cnt > 1)
    {
        pt->length = strlen(pstrs[1]);
        strncpy(pt->buff, pstrs[1], pt->length);
    }
    return 0;
}

int splitcmd(const char *pinput, const char *delimiter, char *tokens[],
             int max_tokens, int *pcount)
{
    int token_count = 0;
    char *token = strtok((char *)pinput, delimiter);

    while (token != NULL && token_count < max_tokens - 1)
    {
        char *pstr = (char *)calloc(1, strlen(token) + 1);
        strcpy(pstr, token);
        printf("Current token is :[%s]\n", token);
        tokens[token_count++] = pstr;
        token = strtok(NULL, delimiter);
    }
    tokens[token_count] = NULL;
    *pcount = token_count;
    for (int i = 0; i < *pcount; i++)
    {
        printf("tokens[%d] = %s\n", i, tokens[i]);
    }
    return 0;
}

const char cmd_cmp[][15] = {"cd",   "ls", "pwd",  "puts",
                            "gets", "rm", "mkdir"}; //  为3~6时需要传文件名
/* Usage: */
int main(int argc, char *argv[])
{
    //  ./client 个人ip地址输入，如：192.168.217.128 约定端口号，如：9876
    ARGS_CHECK(argc, 3);

    // ---------------------------- 连接服务器-------int parseCommand(const char
    // * pinput, int len, train_t * pt)----------------------- //
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    //  创建连接服务器的地址和端口信息
    struct sockaddr_in sockaddr;
    sockaddr.sin_family = AF_INET;
    sockaddr.sin_addr.s_addr = inet_addr(argv[1]);
    sockaddr.sin_port = htons(atoi(argv[2]));

    //  建立socket连接
    int ret = connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
    ERROR_CHECK(ret, -1, "connect");
    if (ret == 0)
    {
        printf("connect successed!please input cmd:\n");
    }
    // ---------------------- 与服务器进行命令交互 ------------------------ //
    //
    //  创建epoll文件对象
    int epfd = epoll_create(1);
    //  创建epoll监听事件集合
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = STDIN_FILENO;
    //  添加监听事件：标准输入
    epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event);
    //  添加监听事件：socket的接收数据（读就绪）
    event.data.fd = sockfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);

    while (1)
    {
        //  构建就绪接受数组
        struct epoll_event events[10];
        //  开始监听
        printf("enter epoll loop\n");
        int num = epoll_wait(epfd, events, 10, -1);
        for (int i = 0; i < num; i++)
        { //  遍历就绪集合
            int cfd = events[i].data.fd;
            if (cfd == STDIN_FILENO)
            {
                //  标准输入就绪
                char buf[60] = {0};
                int flag =
                    0; //  有效命令标识符，1：输入命令有效 0：输入命令无效
                ssize_t sret;
                int check_cmd = -1;
                train_t send_train;
                while (!flag)
                {
                    flag = 0;
                    bzero(buf, sizeof(buf));

                    //  读标准输入
                    sret = read(STDIN_FILENO, buf, sizeof(buf));
                    if (buf[sret - 1] == '\n')
                    {
                        buf[sret - 1] = '\0';
                    }

                    printf("buf: %s, buf's len:%ld\n", buf, strlen(buf));

                    char *pstr[20] = {0};
                    int cnt = 0;
                    splitcmd(buf, " \n", pstr, 20, &cnt);

                    printf("phrase cnt = %d, pstr[0]=%s, pstr[0]'s len:%ld\n",
                           cnt, pstr[0], strlen(pstr[0]));

                    if (cnt < 3)
                    {
                        for (check_cmd = 0; check_cmd < 8; check_cmd++)
                        {
                            if (strncmp(pstr[0], cmd_cmp[check_cmd],
                                        strlen(pstr[0])) == 0)
                            { //  检验输入是否有效

                                flag = 1;
                                send_train._cmdType = check_cmd;
                                printf("cmd = %s\n", cmd_cmp[check_cmd]);

                                //  write(STDOUT_FILENO,buf,sizeof(buf));
                                break;
                            }
                        }
                        if (cnt == 2)
                        {
                            if (check_cmd > 2 && check_cmd < 7)
                            { //  传文件相关命令时，分两段
                                send_train.length = strlen(pstr[1]);
                                strncpy(send_train.buff, pstr[1],
                                        send_train.length);
                                // char filename[20]={0};
                                // strcpy(filename,pstr[1]);
                                // write(STDOUT_FILENO,filename,sizeof(filename));
                            }
                        }
                    }
                    if (flag == 0)
                    {
                        printf("输入无效，请重新输入：\n");
                    }
                }
                //  读字符串装载小火车
                // train_t send_train ;
                // parseCommand(buf,&send_train);
                // send_train.length= sret;
                // send_train._cmdType=check_cmd;
                // if(check_cmd ==3){
                // puts(sockfd,send_train.buff);
                //  发送对端
                send(sockfd, &send_train,
                     sizeof(send_train.length) + send_train.length +
                         sizeof(send_train._cmdType),
                     MSG_WAITALL);

                if (check_cmd == 3)
                { //  输入命令为puts时
                    int puts_rec = puts_client(sockfd, send_train.buff);
                    ERROR_CHECK(puts_rec, -1, "puts");
                    if (puts_rec == 0)
                    {
                        printf("file uploaded successed!!!");
                    }
                    //    int total =
                    //    put_name(send_train.length,send_train.buff);     //
                    //    获取上传文件内容长度 int num = 0; while(num<total){

                    //        train_t file_train;
                    //        if(num+1000>total){
                    //            file_train.length = total-num;
                    //        }
                    //        else{
                    //            file_train.length = 1000;
                    //        }
                    //        file_train.buff = put_file(send_train.buff,num);
                    //
                    //        send(sockfd,&file_train,sizeof(file_train.length)+file_train.length+sizeof(file_train._cmdType),MSG_WAITALL);
                    //        num+=file_train.length;
                    //    }
                }
                //  发送对端
                else
                {
                    int send_cmd_ret =
                        send(sockfd, &send_train,
                             sizeof(send_train.length) + send_train.length +
                                 sizeof(send_train._cmdType),
                             MSG_WAITALL);
                    ERROR_CHECK(send_cmd_ret, -1, "send send_train");
                }

                // if(check_cmd == 3){     //  输入命令为put时
                //     int total = put_name(send_train.length,send_train.buff);
                //     //  获取上传文件内容长度 int num = 0; while(num<total){

                //         train_t file_train;
                //         if(num+1000>total){
                //             file_train.length = total-num;
                //         }
                //         else{
                //             file_train.length = 1000;
                //         }
                //         file_train.buff = put_file(send_train.buff,num);
                //
                //         send(sockfd,&file_train,sizeof(file_train.length)+file_train.length+sizeof(file_train._cmdType),MSG_WAITALL);
                //         num+=file_train.length;
                //     }
                // }
            }
            else if (cfd == sockfd)
            { //  如果从服务器接收文件时
                // 创建一个小火车接收文件名/命令返回值
                train_t rec_train;
                //  先收小火车
                int recv_train_length_ret =
                    recv(sockfd, &rec_train.length, sizeof(rec_train.length),
                         MSG_WAITALL); // 先收火车头
                ERROR_CHECK(recv_train_length_ret, -1, "recv train,length");
                int recv_train_cmdType_ret = recv(sockfd, &rec_train._cmdType,
                                                  sizeof(rec_train._cmdType),
                                                  MSG_WAITALL); //  再收火车类型
                ERROR_CHECK(recv_train_cmdType_ret, -1, "recv train._cmdType");
                int recv_train_buff_ret =
                    recv(sockfd, rec_train.buff, rec_train.length,
                         MSG_WAITALL); //  再收火车车厢
                ERROR_CHECK(recv_train_buff_ret, -1, "recv train.buff");
                //  对端数据到达，socket读就绪
                char buf[1000] = {0};

                memcpy(buf, rec_train.buff,
                       rec_train.length); //  从车厢中取出文件名/命令指令
                if (rec_train._cmdType != 4)
                { //  读取的为gets命令返回数据时
                    // gets(sockfd,buf);
                    //   车厢中的内容为文件
                    //  int fd = open(buf,O_RDWR|O_CREAT|O_TRUNC,0666);     //
                    //  创建一个文件名为buf中内容的文件 bzero(buf,sizeof(buf));
                    //  //  创建一个小火车接收文件
                    //  train_t rec_file;
                    //  while(rec_file.length!=0){
                    //      bzero(rec_file.buff,sizeof(rec_file.buff));
                    //      recv(sockfd,&rec_file.length,sizeof(rec_file.length),0);
                    //      //  先收火车头
                    //      recv(sockfd,rec_file.buff,rec_file.length,MSG_WAITALL);
                    //      //  在接收火车车厢
                    //      write(fd,rec_file.buff,rec_file.length);
                    //}
                    // int filesize = gets_clients(socket,filename); //
                    // 下载文件接口
                    //                    1recvFile(sockfd,)
                    int gets_rec = gets_client(sockfd, &rec_train);
                    ERROR_CHECK(gets_rec, -1, "gets");
                    if (gets_rec == 0)
                    {
                        printf("file download successed!!!");
                    }
                    // //  车厢中的内容为文件
                    // int fd = open(buf,O_RDWR|O_CREAT|O_TRUNC,0666);     //
                    // 创建一个文件名为buf中内容的文件 bzero(buf,sizeof(buf));
                    // //  创建一个小火车接收文件
                    // train_t rec_file;
                    // while(rec_file.length!=0){
                    //     bzero(rec_file.buff,sizeof(rec_file.buff));
                    //     recv(sockfd,&rec_file.length,sizeof(rec_file.length),0);
                    //     //  先收火车头
                    //     recv(sockfd,rec_file.buff,rec_file.length,MSG_WAITALL);
                    //     //  在接收火车车厢
                    //     write(fd,rec_file.buff,rec_file.length);
                    // }
                    //     int filesize = gets_clients(socket,filename); //
                    //     下载文件接口 recvFile(sockfd,)
                }
                else
                { //      车厢内容为命令返回值时
                    write(STDOUT_FILENO, rec_train.buff, rec_train.length);
                }
                //  读数据
                if (rec_train.length == 0)
                {
                    printf("对方断开连接 \n");
                    goto end;
                }
                //  write(STDOUT_FILENO,buf,sizeof(buf));
                // write(STDOUT_FILENO,buf,sizeof(buf));
            }
        }
    }

end:
    close(sockfd);

    return 0;
}
